package org.cybzacg.convert.matcher;


import org.cybzacg.convert.context.ConversionContext;
import org.cybzacg.convert.core.TypeConverter;
import org.cybzacg.convert.enums.ConversionPriority;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 转换匹配器 - 智能匹配转换器
 * 根据源类型、目标类型和上下文信息进行智能匹配
 *
 * @author cybzacg.blog
 * @version 3.1
 * @since 3.1
 */
public class ConversionMatcher {


    /**
     * 匹配转换器
     *
     * @param converters 候选转换器列表
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @param context    转换上下文
     * @return 匹配结果列表，按匹配度降序排列
     */
    public List<MatchResult> matchConverters(
            List<TypeConverter> converters,
            Class<?> sourceType,
            Class<?> targetType,
            ConversionContext context
    ) {
        List<MatchResult> results = new ArrayList<>();

        for (TypeConverter converter : converters) {
            if (converter.supports(targetType)) {
                double score = calculateMatchScore(converter, sourceType, targetType, context);
                String reason = generateMatchReason(converter, sourceType, targetType, score);
                ConversionPriority priority = ConversionPriority.fromValue(converter.getPriority());
                results.add(new MatchResult(converter, score, priority, reason));
            }
        }

        // 按匹配度降序排列，匹配度相同时按优先级升序排列
        return results.stream()
                .sorted((a, b) -> {
                    int scoreCompare = Double.compare(b.getMatchScore(), a.getMatchScore());
                    if (scoreCompare != 0) {
                        return scoreCompare;
                    }
                    return a.getPriority().comparePriority(b.getPriority());
                })
                .collect(Collectors.toList());
    }

    /**
     * 计算匹配度分数
     *
     * @param converter  转换器
     * @param sourceType 源类型
     * @param targetType 目标类型
     * @param context    转换上下文
     * @return 匹配度分数（0.0-1.0）
     */
    private double calculateMatchScore(TypeConverter converter,
                                       Class<?> sourceType,
                                       Class<?> targetType,
                                       ConversionContext context) {
        double score = 0.0;

        // 基础支持分数
        score += 0.3;

        // 类型匹配度分数
        score += calculateTypeMatchScore(converter, sourceType, targetType);

        // 优先级分数
        ConversionPriority priority = ConversionPriority.fromValue(converter.getPriority());
        score += calculatePriorityScore(priority);

        // 上下文匹配分数
        score += calculateContextMatchScore(converter, context);

        // 特殊匹配规则分数
        score += calculateSpecialMatchScore(converter, sourceType, targetType, context);

        return Math.min(1.0, Math.max(0.0, score));
    }

    /**
     * 计算类型匹配度分数
     */
    private double calculateTypeMatchScore(TypeConverter converter,
                                           Class<?> sourceType,
                                           Class<?> targetType) {
        double score = 0.0;

        // 精确类型匹配
        if (isExactTypeMatch(converter, sourceType, targetType)) {
            score += 0.4;
        }

        // 类型兼容性匹配
        if (isTypeCompatible(converter, sourceType, targetType)) {
            score += 0.2;
        }

        // 类型层次匹配
        score += calculateTypeHierarchyScore(converter, sourceType, targetType);

        return score;
    }

    /**
     * 计算优先级分数
     */
    private double calculatePriorityScore(ConversionPriority priority) {
        // 优先级越高，分数越高
        return switch (priority.getGroup()) {
            case SYSTEM -> 0.2;
            case HIGH -> 0.15;
            case MEDIUM -> 0.1;
            case LOW -> 0.05;
            default -> 0.0;
        };
    }

    /**
     * 计算上下文匹配分数
     */
    private double calculateContextMatchScore(TypeConverter converter, ConversionContext context) {
        double score = 0.0;

        // 策略匹配
        if (isStrategyCompatible(converter, context)) {
            score += 0.05;
        }

        // 上下文属性匹配
        score += calculateContextAttributeScore(converter, context);

        return score;
    }

    /**
     * 计算特殊匹配规则分数
     */
    private double calculateSpecialMatchScore(TypeConverter converter,
                                              Class<?> sourceType,
                                              Class<?> targetType,
                                              ConversionContext context) {
        double score = 0.0;

        // null值处理
        if (sourceType == null && canHandleNull(converter)) {
            score += 0.1;
        }

        // 特殊类型处理
        score += calculateSpecialTypeScore(converter, sourceType, targetType);

        // 自定义规则
        score += calculateCustomRuleScore(converter, sourceType, targetType, context);

        return score;
    }

    /**
     * 计算类型层次分数
     */
    private double calculateTypeHierarchyScore(TypeConverter converter,
                                               Class<?> sourceType,
                                               Class<?> targetType) {
        // 根据转换器类型和目标类型的层次关系计算分数
        String converterName = converter.getClass().getSimpleName();

        if (converterName.contains("String") && targetType == String.class) {
            return 0.1;
        }

        if (converterName.contains("Number") && Number.class.isAssignableFrom(targetType)) {
            return 0.1;
        }

        if (converterName.contains("Date") && isDateType(targetType)) {
            return 0.1;
        }

        if (converterName.contains("Collection") && isCollectionType(targetType)) {
            return 0.1;
        }

        return 0.0;
    }

    /**
     * 生成匹配原因
     */
    private String generateMatchReason(
            TypeConverter converter,
            Class<?> sourceType,
            Class<?> targetType,
            double score
    ) {
        StringBuilder reason = new StringBuilder();

        if (isExactTypeMatch(converter, sourceType, targetType)) {
            reason.append("精确类型匹配");
        } else if (isTypeCompatible(converter, sourceType, targetType)) {
            reason.append("类型兼容");
        } else {
            reason.append("基本支持");
        }

        ConversionPriority priority = ConversionPriority.fromValue(converter.getPriority());
        reason.append(", 优先级: ").append(priority.getName());

        if (score > 0.8) {
            reason.append(" (高匹配度)");
        } else if (score > 0.6) {
            reason.append(" (中匹配度)");
        } else {
            reason.append(" (低匹配度)");
        }

        return reason.toString();
    }

    // 辅助方法
    private boolean isExactTypeMatch(TypeConverter converter, Class<?> sourceType, Class<?> targetType) {
        // 检查是否为精确类型匹配
        return converter.getClass().getSimpleName().contains(targetType.getSimpleName());
    }

    private boolean isTypeCompatible(TypeConverter converter, Class<?> sourceType, Class<?> targetType) {
        // 检查类型兼容性
        return converter.supports(targetType);
    }

    private boolean isStrategyCompatible(TypeConverter converter, ConversionContext context) {
        // 检查策略兼容性
        return true; // 简化实现
    }

    private double calculateContextAttributeScore(TypeConverter converter, ConversionContext context) {
        // 计算上下文属性分数
        return 0.0; // 简化实现
    }

    private boolean canHandleNull(TypeConverter converter) {
        // 检查是否可以处理null值
        return true; // 简化实现
    }

    private double calculateSpecialTypeScore(TypeConverter converter, Class<?> sourceType, Class<?> targetType) {
        // 计算特殊类型分数
        return 0.0; // 简化实现
    }

    private double calculateCustomRuleScore(TypeConverter converter, Class<?> sourceType,
                                            Class<?> targetType, ConversionContext context) {
        // 计算自定义规则分数
        return 0.0; // 简化实现
    }

    private boolean isDateType(Class<?> type) {
        return type != null && (type.getName().contains("Date") ||
                type.getName().contains("Time") ||
                type.getName().contains("Instant"));
    }

    private boolean isCollectionType(Class<?> type) {
        return type != null && (type.getName().contains("List") ||
                type.getName().contains("Set") ||
                type.getName().contains("Map") ||
                type.getName().contains("Collection"));
    }
}
